package ar.edu.caece.pl.asin.model.impl;

import ar.edu.caece.pl.alex.model.IToken;
import ar.edu.caece.pl.alex.model.impl.Token;
import ar.edu.caece.pl.asin.manager.IAnalizadorSintactico;
import ar.edu.caece.pl.asin.manager.impl.AbstractAnalizadorSintactico;
import ar.edu.caece.pl.asin.model.ITokenStream;

public class Header extends AbstractAnalizadorSintactico implements IAnalizadorSintactico {
	
	/* INICIALIZACION */	
	public Header ( ITokenStream ts ) {
		super(ts, false);
	}
	public Header ( ITokenStream ts, boolean debugMode ) {
		super(ts,debugMode);
	}
	
	
	/**
	 * Devuelve true si reconoce un bloque de constantes y variables
	 */
	public boolean reconocer () {
		
		boolean recognized = true; //(asumimos correctitud hasta demostrar lo contrario)
		
		//----------------------------------------------
		//Agrego info de debug de la produccion
		em.debug( "Reconocer Header:");		//TODO pasarlo a accion semantica
		//----------------------------------------------
		
		/* <HEADER> -> CONST IDENTIFICADOR : <TIPO_C>; <HEADER> | 
           			   VAR <VAR>; <HEADER> |
           			   LAMBDA				*/
		
		if ( this.getTokenSiguiente().equals( new Token(IToken.PALABRA_RESERVADA_CONST) ) ) {

			//<HEADER> -> CONST IDENTIFICADOR : <TIPO_C>; <HEADER>
			
			//----------------------------------------------
			//Agrego info de debug de la produccion
			em.debug( "<HEADER> -> CONST IDENTIFICADOR : <TIPO_C> <HEADER>", this.getTokenSiguiente() );
			//----------------------------------------------
			
			// Reconocer Palabra Reservada "const"
			if ( !this.reconocerToken(IToken.PALABRA_RESERVADA_CONST) ) {
				//El reconocerToken() habria adelantado el tokenStream hasta salir de esta iteracion del Header,
				//entonces no hay que seguir buscando sino salir
				return false;
			}
			
			// Reconocer Identificador
			if ( !this.reconocerToken(IToken.TYPE_IDENTIFICADOR) ) {
				return false;
			}
			
			//Reconocer Dos Puntos
			if ( !this.reconocerToken(IToken.TYPE_DOS_PUNTOS) ) {
				return false;
			}
			
			// Reconocer TipoC
			if (TipoC.primeros(this.getTokenSiguiente() ) ) {
				
				while ( TipoC.primeros(this.getTokenSiguiente() ) ) {
					
					IAnalizadorSintactico tipoC = new TipoC(this.tokenStream, this.debugMode);
					recognized &= tipoC.reconocer();
				}
				
			} else {
				
				em.error("Se esperaba " + IToken.PALABRA_RESERVADA_NATURAL + 
						" o " + IToken.PALABRA_RESERVADA_INTEGER,
						this.getTokenSiguiente());
				
				//Tratamiento de errores
				em.recover(this.getClass(), this.tokenStream);
				
				return false;			
			}
			
			//Reconocer Dos Puntos
			if ( !this.reconocerToken(IToken.TYPE_PUNTO_COMA) ) {
				return false;
			}
			
		} else if (this.getTokenSiguiente().equals(new Token(IToken.PALABRA_RESERVADA_VAR) ) ) {
			
			// <HEADER> -> VAR <VAR>; <HEADER>

			//----------------------------------------------
			//Agrego info de debug de la produccion
			em.debug( "<HEADER> -> VAR <VAR>; <HEADER>", this.getTokenSiguiente() );
			//----------------------------------------------

			//Reconocer Palabra reservada VAR
			if ( !this.reconocerToken(IToken.PALABRA_RESERVADA_VAR) ) {
				return false;
			}
			
			// Reconocer <VAR>
			if ( Var.primeros(this.getTokenSiguiente() ) ) {

				while ( Var.primeros(this.getTokenSiguiente() ) ) {
					
					IAnalizadorSintactico var = new Var(this.tokenStream, this.debugMode);
					recognized &= var.reconocer();
				}

			} else {
				em.error("Se esperaba " + this.dic.getTokenDescription(IToken.TYPE_IDENTIFICADOR), this.getTokenSiguiente());
				
				//Tratamiento de errores
				em.recover(this.getClass(), this.tokenStream);
				return false;
			}
		}
		return recognized;
	}
	
	public static boolean primeros(IToken token) {
		return  token.equals( new Token(IToken.PALABRA_RESERVADA_CONST) ) ||
				token.equals( new Token(IToken.PALABRA_RESERVADA_VAR) );
	}
	
}
